#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>
#include <stdint.h>
#include "func_record.h"

char *watched = NULL;
FILE *of = NULL;
#define LOG_LEN 1024
#define LOG_EXIT_LEN 64
#define log(fmt...) fprintf(of, fmt)

__attribute__((constructor)) void init()
{
	of = stdout;
	watched = getenv("LOOKIN_FUNC");
}

__attribute__((destructor)) void onexit()
{
        dump_time_stat();
}

int strcat_s(unsigned destLen, char *dest, char *src)
{
	if (strlen(dest) + strlen(src) > destLen) {
		return -1;
	}
	strcat(dest, src);
}

void lookin_log(char *name, char *ty_desc, char *arg_desc, va_list args)
{
	if (of == NULL)
		return;
	log("%s ", name);

	char ch = *ty_desc;
	char *arg_name = arg_desc;
	while (ch != '\0') {
		unsigned len = 0;
		while(*arg_desc != ' ') {
			++arg_desc;
			++len;
		}
		switch (ch) {
			case '1':
				double db = va_arg(args, double);
				log("%.*s %lf ", len, arg_name, db);
				break;
			case '2':
				int integer = va_arg(args, int);
				log("%.*s %d ", len, arg_name, integer);
				break;
			case '5':
				long l = va_arg(args, long);
				log("%.*s %ld ", len, arg_name, l);
				break;
			case '6':
				char *str = va_arg(args, char*);
				log("%.*s %s ", len, arg_name, str);
				break;
			case '7':
				uint8_t *ptr = va_arg(args, uint8_t*);
				log("%.*s %p ", len, arg_name, ptr);
				break;
			case 'z':
			default:
				break;
		}
		ch = *++ty_desc;
		arg_desc++;
		arg_name = arg_desc;
	}
	va_end(args);

	log("\n");
}

void lookin_enter(int idx, char *name, char *ty_desc, char *arg_desc, ...)
{
	record_func(idx, name);
	record_start((unsigned)idx);
	if (watched != NULL && strstr(name, watched) == NULL) {
		return;
	}
	va_list valist;
	va_start(valist, arg_desc);
	lookin_log(name, ty_desc, arg_desc, valist);
}

void lookin_exit(int idx, char *name, char *ty_desc, char *arg_desc, ...)
{
	record_end((unsigned)idx);
	if (watched != NULL && strstr(name, watched) == NULL) {
		return;
	}
	char retMsg[LOG_EXIT_LEN] = {0};
	strcat_s(LOG_EXIT_LEN, retMsg, name);
	strcat_s(LOG_EXIT_LEN, retMsg, "_ret");
	retMsg[LOG_EXIT_LEN-1] = '\0';

	va_list valist;
	va_start(valist, arg_desc);
	lookin_log(retMsg, ty_desc, arg_desc, valist);
}

